package 力扣;

/**
 * 给你一个仅由大写英文字母组成的字符串，你可以将任意位置上的字符替换成另外的字符，总共可最多替换 k 次。在执行上述操作后，找到包含重复字母的最长子串的长度。
 * <p>
 * 注意：字符串长度 和 k 不会超过 104。
 * <p>
 *  
 * <p>
 * 示例 1：
 * <p>
 * 输入：s = "ABAB", k = 2
 * 输出：4
 * 解释：用两个'A'替换为两个'B',反之亦然。
 * 示例 2：
 * <p>
 * 输入：s = "AABABBA", k = 1
 * 输出：4
 * 解释：
 * 将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。
 * 子串 "BBBB" 有最长重复字母, 答案为 4。
 */

public class _424替换后的最长重复字符 {
    // 滑动窗口
    //首先，遍历字符串 s，得到每个元素在字母表中的位置(A 对应位置 0，B 对应位置 1，以此类推)来代替字符串中的每个字符。
    //并且，记录当前窗口中每个元素出现的次数，得到窗口内相同元素的最大个数。
    //若当前窗口中相同元素的最大个数与替换次数 k 之和 < 当前窗口大小(则说明此时不能完全替换掉不同的字母，得到相同字母的子串)，
    // 此时应该使 left 指针右移缩小窗口。
    //时间复杂度：因为只遍历了一次字符串，且字符串的长度为 n，所以复杂度为O(n)
    //空间复杂度：因为开辟了新的空间，所以复杂度为O(n)
    public int characterReplacement(String s, int k) {
        int maxsame = 0;//存储的是窗口内相同元素的最大个数
        int n = s.length();
        int[] arr = new int[26];//arr中存放的当前窗口中每个元素出现的次数
        int left = 0, right;
        for (right = 0; right < n; ++right) {

            //得出索引，ASCLL码----A对应位置0，B对应位置1，以此类推...
            int index = s.charAt(right) - 'A';
            //数目加1，因为我们要求出窗口内最多元素
            arr[index]++;
            //得出最大 maxsame(窗口内相同的元素个数)
            maxsame = Math.max(maxsame, arr[index]);

            //当前窗口中相同元素的最大个数与替换次数之和 < 当前窗口大小
            //(则说明此时不能完全替换掉不同的字母，得到相同字母的子串。)----缩小窗口
            if (maxsame + k < right - left + 1) {

                arr[s.charAt(left) - 'A']--;
                left++;
            }

        }
        return right - left;

    }


    public int characterReplacement2(String s, int k) {
        int len = s.length();
        if (len < 2) {
            return len;
        }

        char[] charArray = s.toCharArray();
        int left = 0;
        int right = 0;

        int res = 0;
        int maxCount = 0;
        int[] freq = new int[26];
        // [left, right) 内最多替换 k 个字符可以得到只有一种字符的子串
        while (right < len) {
            freq[charArray[right] - 'A']++;
            // 在这里维护 maxCount，因为每一次右边界读入一个字符，字符频数增加，才会使得 maxCount 增加
            maxCount = Math.max(maxCount, freq[charArray[right] - 'A']);
            right++;

            if (right - left > maxCount + k) {
                // 说明此时 k 不够用
                // 把其它不是最多出现的字符替换以后，都不能填满这个滑动的窗口，这个时候须要考虑左边界向右移动
                // 移出滑动窗口的时候，频数数组须要相应地做减法
                freq[charArray[left] - 'A']--;
                left++;
            }
            res = Math.max(res, right - left);
        }
        return res;
    }


}
